//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  
    Pxa_ohci.cpp
    
Abstract:  
    PXA Chip dependant part of the USB Open Host Controller Driver (OHCD).

Notes: 
--*/
#include <windows.h>
#include <ceddk.h>

//#define DEBUG
//#undef DEBUGMSG
//#undef ZONE_INIT
//#define DEBUGMSG RETAILMSG
//#define ZONE_INIT 1
//#define ZONE_ERROR 1

#include <hcdddsi.h>

#include <monahans_usbohci.h>
#include "monahans_base_regs.h"
#include "monahans.h"
#include "xllp_clkmgr.h"
#include "xllp_intc.h"
#include <nkintr.h> // needed for SYSINTR_NOP

// Constant
static const DWORD gcTotalAvailablePhysicalMemory = 65536; // 64K
static const DWORD gcHighPriorityPhysicalMemory = 0x4000; // 16K

SOhcdPdd::SOhcdPdd (LPCTSTR lpActiveRegistry)
:   CMiniThread( 0, TRUE )
,   CRegistryEdit(HKEY_LOCAL_MACHINE, lpActiveRegistry )
{
    m_pDCCLKReg = NULL;
    m_pDCUSBOHCIReg = NULL;
    m_pvDmaVirtualAddress = NULL;             // DMA buffers as seen by the CPU
    m_dwDamBufferSize = 0;
    m_dwSysIntr = SYSINTR_UNDEFINED;
	m_dwSysIntrNoOHCI =SYSINTR_UNDEFINED;
	
    m_IsrHandle = NULL;
    m_bIsBuiltInDma = TRUE;
    m_pobMem = NULL;
    m_pobOhcd = NULL;
    m_hParentBusHandle =  CreateBusAccessHandle((LPCWSTR)g_dwContext);
    m_lpDriverReg = NULL;
	m_hISTEvent =0;

    m_XllpHandle.pUSBHRegs=NULL;    // Pointer to USB Host registers
    m_XllpHandle.pUdcRegs=NULL;// Pointer to USB Client registers
    m_XllpHandle.pMfpRegs=NULL;  // Pointer to MFP registers
    m_XllpHandle.pCLKMGRRegs=NULL;    // Pointer to the Clock Manager registers
    m_XllpHandle.pOSTRegs=NULL;          // Pointer to OST registers
    m_XllpHandle.pPlatformUSBHConfig=&m_Platform;; //Pointer to Platform Specific USBH Configuration

	m_IPMID =0;
	
    if (lpActiveRegistry) {
        DWORD dwLen = _tcslen(lpActiveRegistry);
        m_lpDriverReg = new TCHAR [ dwLen +1 ];
        if (m_lpDriverReg) {
            _tcscpy(m_lpDriverReg,lpActiveRegistry);
            m_lpDriverReg [ dwLen ] =0;
        }
    }
}
SOhcdPdd::~SOhcdPdd ()
{
    m_bTerminated=TRUE;
    DisablePddInterrupts();
    //
    if (m_IsrHandle) {
        FreeIntChainHandler(m_IsrHandle);
    }
    
    if ( m_pobOhcd )
        HcdMdd_DestroyHcdObject( m_pobOhcd );
    if (m_pobMem)
        HcdMdd_DestroyMemoryObject(m_pobMem);
    
    if (m_pvDmaVirtualAddress) {        
        if (m_bIsBuiltInDma) {
            MmUnmapIoSpace(m_pvDmaVirtualAddress,0);
        }
        else {
            HalFreeCommonBuffer(&m_AdapterObject, m_dwDamBufferSize, m_DmaPhysicalAddr, m_pvDmaVirtualAddress, FALSE);
        }
    }
    if (m_lpDriverReg)
    {
        delete m_lpDriverReg;
        m_lpDriverReg=NULL;
    }
    
    if (m_pDCCLKReg)
    {
        MmUnmapIoSpace((PVOID)m_pDCCLKReg,0);
        m_pDCCLKReg=NULL;
    }
    if (m_pDCUSBOHCIReg)
    {
        MmUnmapIoSpace((PVOID)m_pDCUSBOHCIReg,0);
        m_pDCUSBOHCIReg=NULL;
    }
    if (m_XllpHandle.pUdcRegs)
    {
        MmUnmapIoSpace((PVOID)m_XllpHandle.pUdcRegs,0);
        m_XllpHandle.pUdcRegs=NULL;
    }
    if (m_XllpHandle.pMfpRegs)
    {
        MmUnmapIoSpace((PVOID)m_XllpHandle.pMfpRegs,0);
        m_XllpHandle.pMfpRegs=NULL;
    }
    if (m_XllpHandle.pOSTRegs)
    {
        MmUnmapIoSpace((PVOID)m_XllpHandle.pOSTRegs,0);
        m_XllpHandle.pOSTRegs=NULL;
    }
    if (m_pvDmaVirtualAddress) 
	{        
        if (m_bIsBuiltInDma) {
            MmUnmapIoSpace(m_pvDmaVirtualAddress,0);
        }
        else {
            HalFreeCommonBuffer(&m_AdapterObject, m_dwDamBufferSize, m_DmaPhysicalAddr, m_pvDmaVirtualAddress, FALSE);
        }
    }
	
    if (m_hParentBusHandle)
    {
        CloseBusAccessHandle(m_hParentBusHandle);
        m_hParentBusHandle=NULL;
    }
	if( m_dwSysIntrNoOHCI != SYSINTR_UNDEFINED )
	{
		KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntrNoOHCI, sizeof(DWORD),NULL,0,NULL);
		m_dwSysIntrNoOHCI=SYSINTR_UNDEFINED;
	}
    if( m_hISTEvent )
   	{
   		CloseHandle(m_hISTEvent);
		m_hISTEvent=0;
   	}

	if ( IPM_DeRegister(m_IPMID,3000)==IPM_STATUS_SUCCESS)
		RETAILMSG(1, (_T("[IPM HCD1] De-Registration Completed OK\n")));
	else
		RETAILMSG(1, (_T("[IPM HCD1] De-Registration FAILED\n")));
}

BOOL SOhcdPdd::Init()
{
    //Map Clock
    {
        PHYSICAL_ADDRESS ioPhysicalBase = { MONAHANS_BASE_REG_PA_CLKMGR, 0};
        m_XllpHandle.pCLKMGRRegs=m_pDCCLKReg = (P_XLLP_CLKMGR_T)MmMapIoSpace(ioPhysicalBase, sizeof(P_XLLP_CLKMGR_T),FALSE);
        DEBUGMSG(ZONE_INIT, (_T("Clock register base address 0x%x\r\n"), m_XllpHandle.pCLKMGRRegs));
    }
    //map usb host
    {
        PHYSICAL_ADDRESS ioPhysicalBase = { MONAHANS_BASE_REG_PA_USBH, 0};
        m_pDCUSBOHCIReg = (PPXA_USBOHCI_REG)MmMapIoSpace(ioPhysicalBase, sizeof(PXA_USBOHCI_REG),FALSE);
        m_XllpHandle.pUSBHRegs=(P_XLLP_USBOHCI_T)m_pDCUSBOHCIReg;
        DEBUGMSG(ZONE_INIT, (_T("USB host register base address 0x%x\r\n"), m_XllpHandle.pUSBHRegs));
    }
    //map usb client
    {
        PHYSICAL_ADDRESS ioPhysicalBase = { MONAHANS_BASE_REG_PA_UDC, 0};
        m_XllpHandle.pUdcRegs = (P_XLLP_UDC_REGISTERS_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_UDC_REGISTERS_T),FALSE);
        DEBUGMSG(ZONE_INIT, (_T("UDC host register base address 0x%x\r\n"), m_XllpHandle.pUdcRegs));
    }
    //map mfp 
    {
        PHYSICAL_ADDRESS ioPhysicalBase = { MONAHANS_BASE_REG_PA_MFP, 0};
        m_XllpHandle.pMfpRegs = (P_XLLP_VUINT32_T)MmMapIoSpace(ioPhysicalBase, 0x800,FALSE);
        DEBUGMSG(ZONE_INIT, (_T("MFP host register base address 0x%x\r\n"), m_XllpHandle.pMfpRegs));
    }
    //map OST
    {
        PHYSICAL_ADDRESS ioPhysicalBase = { MONAHANS_BASE_REG_PA_OST, 0};
        m_XllpHandle.pOSTRegs = (P_XLLP_OST_T)MmMapIoSpace(ioPhysicalBase, sizeof(XLLP_OST_T),FALSE);
        DEBUGMSG(ZONE_INIT, (_T("MFP host register base address 0x%x\r\n"), m_XllpHandle.pOSTRegs));
    }
//IPM Support
	IPM_STATUS_T status;
	status = IPM_Register(_T("HCD1:"), &m_IPMID ,3000);
	if ( status==IPM_STATUS_SUCCESS)
	{
		DWORD dwProcState;
		RETAILMSG (1, (_T("[IPM HCD1] Registration Completed, client id is %d\r\n"),m_IPMID));

		dwProcState = IPM_PROCESSOR_D0_RDY | IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D2_RDY| IPM_PROCESSOR_D1_RDY; // Initial

		// Notify IPM 
		if ( IPM_NotifyReadyForProcState(m_IPMID, dwProcState ,3000)==IPM_STATUS_SUCCESS)
		{
			RETAILMSG(1, (_T("[IPM HCD1] Notify IPM Ready For Processor state for driver Success!\r\n")));
		}
		else
		{
			RETAILMSG(1, (_T("[IPM HCD1] Notify IPM Ready For Processor state for driver Fail!\r\n")));
		}
	}
	else
		RETAILMSG(1, (_T("[IPM HCD1] Registration Failed with error code %d\r\n"),status));

//Interrupt Support
	DWORD Irq= IRQ_USBNONOHCI;
	if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(DWORD), &(m_dwSysIntrNoOHCI), sizeof(DWORD), NULL))
    {
        // invalid SDIO SYSINTR value!
        RETAILMSG(1, (TEXT("Error obtaining USB Host 2 SYSINTR value!\n")));
        m_dwSysIntrNoOHCI = SYSINTR_UNDEFINED;
        return FALSE;
    }


	m_hISTEvent= CreateEvent(0,FALSE,FALSE,NULL);
    if (m_hISTEvent!=NULL)
   	{
        if(! InterruptInitialize(m_dwSysIntrNoOHCI,m_hISTEvent,0,0))
        {
        		RETAILMSG(1,(_T("OHCI Initialize irq failed\r\n")));
				return FALSE;
        }
   	}
    else
       return FALSE;

	ThreadStart();

	DEBUGMSG(ZONE_INIT,(_T("System Irq %d , irq%d, event 0x%x\r\n"), m_dwSysIntrNoOHCI,Irq, m_hISTEvent));

	BOOL ret=FALSE;
    if (m_pDCCLKReg 
        && m_pDCUSBOHCIReg 
        && m_XllpHandle.pUdcRegs 
        && m_XllpHandle.pMfpRegs
        && m_XllpHandle.pOSTRegs 
        && IsKeyOpened()) 
    {
        TurnOnUSBHostClocks();

        ret= (InitPddInterrupts() && OHCI_Reset() && InitializeOHCI());
    }

	return ret;
}
BOOL SOhcdPdd::InitializeOHCI()
{
    PUCHAR ioPortBase = NULL;
    DWORD dwAddrLen;
    DWORD dwIOSpace;
    BOOL InstallIsr = FALSE;
    BOOL fResult = FALSE;
    LPVOID pobMem = NULL;
    LPVOID pobOhcd = NULL;
    DWORD PhysAddr;
    HKEY hKey=NULL;

    DDKWINDOWINFO dwi;
    DDKISRINFO dii;

    // Setup Memory Windows For OHCI MDD code.
    dwi.cbSize=sizeof(dwi);
    PhysAddr = dwi.memWindows[0].dwBase = MONAHANS_BASE_REG_PA_USBH;
    dwAddrLen= dwi.memWindows[0].dwLen = 0x1000;
    dwi.dwInterfaceType = Internal;
    dwi.dwBusNumber = 0;
    dwi.dwNumMemWindows =1;
    dwIOSpace = 0;
        
    dii.cbSize=sizeof(dii);
    if (GetIsrInfo(&dii)  != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR,(TEXT("InitializeOHCI:DDKReg_GetWindowInfo or  DDKReg_GetWindowInfo failed\r\n")));
        return FALSE;
    }
    // Overwrite the item we know.
    dii.dwIrq = XLLP_INTC_S_USBH1;
    m_dwSysIntr = dii.dwSysintr;
    DEBUGMSG(ZONE_INIT,(TEXT("OHCD: Read config from registry: Base Address: 0x%X, Length: 0x%X, I/O Port: %s, SysIntr: 0x%X, Interface Type: %u, Bus Number: %u\r\n"),
                    PhysAddr, dwAddrLen, dwIOSpace ? L"YES" : L"NO", dii.dwSysintr, dwi.dwInterfaceType, dwi.dwBusNumber));
    
    ioPortBase = (PBYTE) PhysAddr;
    
    if (dii.szIsrDll[0] != 0 && dii.szIsrHandler[0]!=0 && dii.dwIrq<0xff && dii.dwIrq>0 ) {
        // Install ISR handler
        m_IsrHandle = LoadIntChainHandler(dii.szIsrDll, dii.szIsrHandler, (BYTE)dii.dwIrq);

        if (!m_IsrHandle) {
            DEBUGMSG(ZONE_ERROR, (L"OHCD: Couldn't install ISR handler\r\n"));
        } else {
            GIISR_INFO Info;
            PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};
            
            DEBUGMSG(ZONE_INIT, (L"OHCD: Installed ISR handler, Dll = '%s', Handler = '%s', Irq = %d\r\n",
                dii.szIsrDll, dii.szIsrHandler, dii.dwIrq));
            
            if (!BusTransBusAddrToStatic(m_hParentBusHandle,(INTERFACE_TYPE)dwi.dwInterfaceType, dwi.dwBusNumber, PortAddress, dwAddrLen, &dwIOSpace, (PVOID *)&PhysAddr)) {
                DEBUGMSG(ZONE_ERROR, (L"OHCD: Failed TransBusAddrToStatic\r\n"));
                return FALSE;
            }
        
            // Set up ISR handler
            Info.SysIntr = dii.dwSysintr;
            Info.CheckPort = TRUE;
            Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE;
            Info.UseMaskReg = TRUE;
            Info.PortAddr = PhysAddr + 0x0C;
            Info.PortSize = sizeof(DWORD);
            Info.MaskAddr = PhysAddr + 0x10;
            
            if (!KernelLibIoControl(m_IsrHandle, IOCTL_GIISR_INFO, &Info, sizeof(Info), NULL, 0, NULL)) {
                DEBUGMSG(ZONE_ERROR, (L"OHCD: KernelLibIoControl call failed.\r\n"));
            }
        }
    }
    DWORD dwDmaBase = 0;
    DWORD dwHPPhysicalMemSize = 0;
    if (!GetRegValue(PXA_REG_DMA_BUFFER_PH_ADDR_VAL_NAME, (PBYTE)&dwDmaBase,PXA_REG_DMA_BUFFER_PH_ADDR_VAL_LEN)) {
        DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::Init - Cann't get \"%s\" registry value.\r\n"),PXA_REG_DMA_BUFFER_PH_ADDR_VAL_NAME));
        dwDmaBase = 0;
    }
    if (!GetRegValue(PXA_REG_DMA_BUFFER_LENGTH_VAL_NAME, (PBYTE)&m_dwDamBufferSize,PXA_REG_DMA_BUFFER_LENGTH_VAL_LEN)) {
        DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::Init - Cann't get \"%s\" registry value.\r\n"),PXA_REG_DMA_BUFFER_LENGTH_VAL_NAME));
        m_dwDamBufferSize = 0;
    }
    if (dwDmaBase && m_dwDamBufferSize) {
        m_DmaPhysicalAddr.LowPart = dwDmaBase;
        m_DmaPhysicalAddr.HighPart = 0;
        m_pvDmaVirtualAddress = MmMapIoSpace(m_DmaPhysicalAddr,m_dwDamBufferSize, FALSE);
        dwHPPhysicalMemSize = m_dwDamBufferSize / 4  ; 
        m_bIsBuiltInDma = TRUE;
    }
    else { // we locate DMA buffer from public pool
        // The PDD can supply a buffer of contiguous physical memory here, or can let the 
        // MDD try to allocate the memory from system RAM.  We will use the HalAllocateCommonBuffer()
        // API to allocate the memory and bus controller physical addresses and pass this information
        // into the MDD.
        if (GetRegValue(REG_PHYSICAL_PAGE_SIZE, (PBYTE)&m_dwDamBufferSize, REG_PHYSICAL_PAGE_SIZE_LEN)) {
            dwHPPhysicalMemSize = m_dwDamBufferSize/4;
            m_dwDamBufferSize = (m_dwDamBufferSize+ PAGE_SIZE -1) & ~(PAGE_SIZE -1);
            // Align with page size.        
            dwHPPhysicalMemSize = ((dwHPPhysicalMemSize +  PAGE_SIZE -1) & ~(PAGE_SIZE -1));
        }
        else 
            m_dwDamBufferSize=0;
        
        if (m_dwDamBufferSize<gcTotalAvailablePhysicalMemory) { // Setup Minimun requirement.
            m_dwDamBufferSize = gcTotalAvailablePhysicalMemory;
            dwHPPhysicalMemSize = gcHighPriorityPhysicalMemory;
        }

        m_AdapterObject.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
        m_AdapterObject.InterfaceType = Internal;
        m_AdapterObject.BusNumber = 0 ;
        if ((m_pvDmaVirtualAddress = HalAllocateCommonBuffer(&m_AdapterObject, m_dwDamBufferSize, &m_DmaPhysicalAddr, FALSE)) == NULL) {
            DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::InitializeOHCI() - HalAllocateCommonBuffer return FALSE!!!\r\n.\r\n")));
            return FALSE;
        }
        m_bIsBuiltInDma = FALSE;
    }
    if (m_pvDmaVirtualAddress == NULL || 
            !(m_pobMem = HcdMdd_CreateMemoryObject(m_dwDamBufferSize, dwHPPhysicalMemSize, (PUCHAR) m_pvDmaVirtualAddress, (PUCHAR) m_DmaPhysicalAddr.LowPart))) {
        DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::InitializeOHCI() - Cann't CreateMemoryObject!!!\r\n.\r\n")));
        return FALSE;
    }

    if (!( m_pobOhcd  = HcdMdd_CreateHcdObject(this, m_pobMem, m_lpDriverReg, (PUCHAR)m_pDCUSBOHCIReg, m_dwSysIntr))) {
        DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::InitializeOHCI() - Cann't CreateHcdObject!!!\r\n.\r\n")));
        return FALSE;
    }

    HcdMdd_SetCapability (m_pobOhcd,HCD_ROOT_HUB_INTERRUPT);
	
	
    return TRUE;
}
DWORD SOhcdPdd::ThreadRun() 
{	
	DWORD TimeOut=INFINITE;
	
	RETAILMSG(1,(_T("Thread Run\r\n")));
	while(1)
	{
		DWORD wait=WaitForSingleObject(m_hISTEvent, TimeOut);
		
		if( (wait != WAIT_OBJECT_0) &&   (wait != WAIT_TIMEOUT) )
		{
			DEBUGMSG(ZONE_ERROR, (_T("Wait Single Object Fail  Error \r\n"), GetLastError()));
			continue;
		}
		//XllpClockEnable(m_XllpHandle.pCLKMGRRegs, XLLP_CLK_USBH, XLLP_TRUE);
		
		DWORD uhcstat=m_pDCUSBOHCIReg->uhcstat;
		m_pDCUSBOHCIReg->uhcstat=uhcstat;
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_UPS3 )
		{
			RETAILMSG(1, (_T("USB Power Sense Port3\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_SBMAI )
		{
			RETAILMSG(1, (_T("USB System Bus Master Abort Interrup\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_SBTAI )
		{
			RETAILMSG(1, (_T("USB System Bus Target Abort Interrupt\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_UPRI )
		{
			RETAILMSG(1, (_T("USB System Port Resume Interrupt\r\n")));
			
		}


		if(TimeOut!=INFINITE)
		{
			if( (m_pDCUSBOHCIReg->uhcrhps1 & XLLP_USBOHCI_UHCRHPS_CCS )||
			  (m_pDCUSBOHCIReg->uhcrhps2 & XLLP_USBOHCI_UHCRHPS_CCS )||
			  (m_pDCUSBOHCIReg->uhcrhps3 & XLLP_USBOHCI_UHCRHPS_CCS ))
			{
								
			}else
			{
				DEBUGMSG(ZONE_INIT,(_T("All Usb device removed\r\n")));
				m_pDCUSBOHCIReg->uhchie |= XLLP_USBOHCI_UHCSTAT_HBA;
				TimeOut=INFINITE;
				if ( (IPM_NotifyReadyForProcState(m_IPMID, IPM_PROCESSOR_D0_RDY|IPM_PROCESSOR_RING_OSC_RDY | IPM_PROCESSOR_D2_RDY| IPM_PROCESSOR_D1_RDY ,1000)!=IPM_STATUS_SUCCESS)||
				    (IPM_ReleaseMinOp(m_IPMID, 3000) != IPM_STATUS_SUCCESS) )
					RETAILMSG(1, (_T("USBOTG: IPM_ReleaseMinOp failed\r\n")));
				
			}
		}
		
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_UPS2 )
		{
			RETAILMSG(1, (_T("USB Power Sense Port2\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_UPS1 )
		{
			RETAILMSG(1, (_T("USB Power Sense Port1\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_HTA )
		{
			RETAILMSG(1, (_T("USB HCI Transfer Abort\r\n")));
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_HBA )
		{
			DEBUGMSG(ZONE_INIT,( _T("USB HCI Buffer Active\r\n")));
			m_pDCUSBOHCIReg->uhchie &= ~XLLP_USBOHCI_UHCSTAT_HBA;

			if (  (IPM_NotifyReadyForProcState(m_IPMID, IPM_PROCESSOR_D0_RDY ,1000)!=IPM_STATUS_SUCCESS)||
			    (IPM_SetMinOp(m_IPMID,IPM_OP_104MHZ, 3000) != IPM_STATUS_SUCCESS))
					RETAILMSG(1, (_T("USBOTG: IPM_SetMinOp failed\r\n")));
			
			TimeOut=100;
				
		}
		if(uhcstat & XLLP_USBOHCI_UHCSTAT_RWUE )
		{
			RETAILMSG(1, (_T("USB HCI Remote Wake Up\r\n")));
		}
		InterruptDone(m_dwSysIntrNoOHCI);
	}
	return 0;
}
BOOL SOhcdPdd::InitPddInterrupts()
{
    DEBUGMSG(ZONE_INIT, (TEXT("SOhcdPdd::InitPddInterrupts() - Initial UHCHIE = 0x%x\r\n"),m_pDCUSBOHCIReg->uhchie));
    m_pDCUSBOHCIReg->uhchie = 

		XLLP_USBOHCI_UHCHIE_RWIE   |
		XLLP_USBOHCI_UHCHIE_HBAIE  |
		XLLP_USBOHCI_UHCHIE_TAIE   |
//		XLLP_USBOHCI_UHCHIE_UPS1IE |
		XLLP_USBOHCI_UHCHIE_UPS2IE |
		XLLP_USBOHCI_UHCHIE_UPRIE  |
//		XLLP_USBOHCI_UHCHIE_UPS3IE |

		0 ; 
    return TRUE;
}

BOOL SOhcdPdd::OHCI_Reset()
{
    DEBUGMSG(ZONE_INIT,(TEXT("OHCI_Reset: Resetting PXA OHCI.\r\n")));

    XllpUsbhPowerUp(&m_XllpHandle);
            
    DEBUGMSG(m_pDCUSBOHCIReg,(TEXT("OHCI_Reset: done.\r\n")));
    return TRUE;
}

/// TurnOnUSBHostClocks:
///      This routine will make sure that the USB Host OHCI block in the
///      PXA core is getting clocks. If it is not getting clocks,
///      then some accesses to it may stall, especially if one needs to
///      wait for some OHCI register bits to change.
void
SOhcdPdd::TurnOnUSBHostClocks()
{
    // The clock enable bit for the USB Host OHCI block in PXA
    // is bit number 20.
    XllpClockEnable((P_XLLP_CLKMGR_T)m_pDCCLKReg, XLLP_CLK_USBH, XLLP_TRUE);
 
}


/// TurnOffUSBHostClocks:
///      This routine will make sure that the USB Host OHCI block in the
///      PXA core is not getting clocks. If it is not getting clocks,
///      then there will be power savings.
void
SOhcdPdd::TurnOffUSBHostClocks()
{
    // The clock enable bit for the USB Host OHCI block in PXA
    // is bit number 20.
    XllpClockEnable((P_XLLP_CLKMGR_T)m_pDCCLKReg, XLLP_CLK_USBH, XLLP_FALSE);}

// Manage WinCE suspend/resume events

DWORD SOhcdPdd::InitiatePowerUp()
{
    DEBUGMSG(ZONE_INIT,(TEXT("SOhcdPdd::InitiatePowerUp: m_pDCUSBOHCIReg: %08x.\r\n"), m_pDCUSBOHCIReg));
	if( m_XllpHandle.pOSTRegs )
	    XllpUsbhPowerUp(&m_XllpHandle);
    return 0;
}
void SOhcdPdd::PowerUp()
{
	DEBUGMSG(ZONE_INIT,(TEXT("SOhcdPdd::InitiatePowerUp: m_pDCUSBOHCIReg: %08x.\r\n"), m_pDCUSBOHCIReg));

	if( m_XllpHandle.pOSTRegs )
	    XllpUsbhPowerUp(&m_XllpHandle);

	if( m_pobOhcd )
	    HcdMdd_PowerUp(m_pobOhcd);
}

void SOhcdPdd::PowerDown()
{

    // let the MDD do its processing (including putting the HC into reset)
    HcdMdd_PowerDown(m_pobOhcd);

    // disable the USB port as described in spec
    // chip documentation:
    // (1) Reset HC (done by MDD)
    // (2) wait 10 us
    // (3) clear global power enable bit
    // (4) set the standby enable bit
    // (5) stop the usb clock
    //usWait(10);                     // must not block or do operations illegal in interrupt context
    XllpUsbhPowerDown(&m_XllpHandle);
};


/* HcdPdd_DllMain
 * 
 *  DLL Entry point.
 *
 * @remarks 	Do nothing
 * 
 */
extern "C" BOOL HcdPdd_DllMain(HANDLE /*hinstDLL*/, DWORD /*dwReason*/, LPVOID /*lpvReserved*/)
{
    return TRUE;
}

/// This gets called by the MDD's IST when it detects a power resume.
/// @param  	hDeviceContext  [IN] SOhcdPdd object
extern "C" void HcdPdd_InitiatePowerUp (DWORD hDeviceContext)
{
    SOhcdPdd * pPddObject = (SOhcdPdd *)hDeviceContext;
    if (pPddObject)
        pPddObject->InitiatePowerUp();
    
    return;
}


/** HcdPdd_Init
 *
 *   PDD Entry point - called at system init to detect and configure UHCI card.
 *
 * @param  	dwContext  [IN] Pointer to context value. For device.exe, this is a string
 *							 indicating our active registry key.
 * @return
 *   Return pointer to PDD specific data structure, or NULL if error.
 */
extern "C" DWORD 
HcdPdd_Init(
    DWORD dwContext)  // IN - Pointer to context value. For device.exe, this is a string 
                      //      indicating our active registry key.
{
    SOhcdPdd *  pPddObject = CreatePXAOhci((LPCTSTR)dwContext);

    if (pPddObject && pPddObject->Init()) {
        DEBUGMSG(ZONE_INIT, (TEXT("HcdPdd_Init: Checking SW18 - controls OHCI loading.\r\n")));
        return (DWORD) pPddObject ;
    }
    if (pPddObject)
        delete pPddObject;
    return (DWORD)NULL;
}

/** HcdPdd_CheckConfigPower
 *
 *    Check power required by specific device configuration and return whether it
 *    can be supported on this platform.  For CEPC, this is trivial, just limit to
 *    the 500mA requirement of USB.  For battery powered devices, this could be 
 *    more sophisticated, taking into account current battery status or other info.
 *
 * @param 	bPort 			[IN]Port number
 * @param 	dwCfgPower 		[IN]Power required by configuration
 * @param 	dwTotalPower 		[IN]Total power currently in use on port
 *
 * @return 
 *    Return TRUE if configuration can be supported, FALSE if not.
 */
extern "C" BOOL HcdPdd_CheckConfigPower(
    UCHAR bPort,         // IN - Port number
    DWORD dwCfgPower,    // IN - Power required by configuration
    DWORD dwTotalPower)  // IN - Total power currently in use on port
{
    return ((dwCfgPower + dwTotalPower) > 500) ? FALSE : TRUE;
}


/// PDD Power up, called when System resume
/// Call SOhcdPdd::PowerUp
/// @param  	hDeviceContext  [IN] SOhcdPdd object
extern "C" void HcdPdd_PowerUp(DWORD hDeviceContext)
{
    SOhcdPdd * pPddObject = (SOhcdPdd *)hDeviceContext;
    DEBUGMSG(ZONE_INIT, (TEXT("HcdPdd_PowerUp: enter.\n\r")));
    if (pPddObject)
        pPddObject->PowerUp();
    DEBUGMSG(ZONE_INIT, (TEXT("HcdPdd_PowerUp: Need to add PXA support.\n\r")));
    return;
}

/// PDD Power Down, called when System suspend
/// Call SOhcdPdd::PowerDown
/// @param  	hDeviceContext  [IN] SOhcdPdd object
extern "C" void HcdPdd_PowerDown(DWORD hDeviceContext)
{
    SOhcdPdd * pPddObject = (SOhcdPdd *)hDeviceContext;
    DEBUGMSG(ZONE_INIT, (TEXT("HcdPdd_PowerDown: enter.\n\r")));

    if (pPddObject)
        pPddObject->PowerDown();

    DEBUGMSG(ZONE_INIT, (TEXT("HcdPdd_PowerDown: Need to add PXA support.\n\r")));
    return;
}

/// Deinit PDD
/// @param  	hDeviceContext  [IN] SOhcdPdd object
/// @return     Always TRUE
extern "C" BOOL HcdPdd_Deinit(DWORD hDeviceContext)
{
    SOhcdPdd * pPddObject = (SOhcdPdd *)hDeviceContext;
    if (pPddObject)
        delete pPddObject;
    return TRUE;
}

///Do nothing
extern "C" DWORD HcdPdd_Open(DWORD /*hDeviceContext*/, DWORD /*AccessCode*/,
        DWORD /*ShareMode*/)
{

    return 1; // we can be opened, but only once!
}

///Do nothing
extern "C" BOOL HcdPdd_Close(DWORD /*hOpenContext*/)
{
    return TRUE;
}

///Do nothing
extern "C" DWORD HcdPdd_Read(DWORD /*hOpenContext*/, LPVOID /*pBuffer*/, DWORD /*Count*/)
{
    return (DWORD)-1; // an error occured
}

///Do nothing
extern "C" DWORD HcdPdd_Write(DWORD /*hOpenContext*/, LPCVOID /*pSourceBytes*/,
        DWORD /*NumberOfBytes*/)
{
    return (DWORD)-1;
}

///Do nothing
extern "C" DWORD HcdPdd_Seek(DWORD /*hOpenContext*/, LONG /*Amount*/, DWORD /*Type*/)
{
    return (DWORD)-1;
}

///Do nothing
extern "C" BOOL HcdPdd_IOControl(DWORD /*hOpenContext*/, DWORD /*dwCode*/, PBYTE /*pBufIn*/,
        DWORD /*dwLenIn*/, PBYTE /*pBufOut*/, DWORD /*dwLenOut*/, PDWORD /*pdwActualOut*/)
{
    return FALSE;
}

///Use standord function to remove CRT warning
extern "C" BOOL
DllEntry(
    HANDLE hDllHandle,
    DWORD  dwReason, 
    LPVOID lpReserved
    )
{
   return DllMain(hDllHandle,dwReason,lpReserved);
}

